package com.shockweb.service.ioc.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.shockweb.common.utils.classmethod.ClassMethod;
import com.shockweb.common.utils.classmethod.ClassMethodParamDefine;
import com.shockweb.bridge.ServiceRequest;
import com.shockweb.service.ServiceServerException;
import com.shockweb.service.ioc.IocInvoke;
import com.shockweb.service.ioc.defaultconfig.Service;

import javassist.NotFoundException;

/**
 * 默认的Ioc管理器，负责执行微服务
 * 
 * @author 彭明华
 * 2018年1月19日 创建
 */
public class DefaultIocInvokeImpl implements IocInvoke{
	
	/**
	 * 配置文件所有服务定义
	 */
	private Map<String,Service> beanDefines = new HashMap<String,Service>();
	
	/**
	 * class定义
	 */
	private Map<String,Class<?>> classes = new HashMap<String,Class<?>>();
	
	/**
	 * 实例化的bean
	 */
	private Map<String,Object> beans = new HashMap<String,Object>();
	
	/**
	 * 构造方法
	 * @param beans
	 */
	public DefaultIocInvokeImpl(Map<String,Service> beanDefines)throws ServiceServerException{
		this.beanDefines = beanDefines;
		if(beanDefines!=null){
			Iterator<Entry<String,Service>> its = beanDefines.entrySet().iterator();
			while(its.hasNext()){
				Entry<String,Service> entry = its.next();
				Service service = entry.getValue();
				try{
					if(!classes.containsKey(service.getClazz())){
						classes.put(service.getClazz(), Class.forName(service.getClazz()));
					}
				}catch(Exception e){
					throw new ServiceServerException("加载class '" + service.getClazz() + "'出错",e);
				}
				try{
					if(service.getScope()==null || service.getScope().equals("singleton")){
						if(!beans.containsKey(entry.getKey())){
							beans.put(entry.getKey(), classes.get(service.getClazz()).newInstance());
						}
					}else if(service.getScope().equals("prototype")){
	
					}else{
						throw new ServiceServerException("非法的Scope '" + service.getScope() + "'");
					}
				}catch(ServiceServerException e){
					throw e;
				}catch(Exception e){
					throw new ServiceServerException("实例化name '" + entry.getKey() + "''s class '" + service.getClazz() + "'出错",e);
				}
			}
			
		}
	}

	/**
	 * @see IocInvoke#ableInvoke(String)
	 */
	public boolean ableInvoke(String serviceName) {
		if(beanDefines!=null){
			return beanDefines.containsKey(serviceName);
		}
		return false;
	}
	
	/**
	 * @see IocInvoke#invoke(String, ServiceRequest)
	 */
	public Object invoke(String serviceName,ServiceRequest req) throws ServiceServerException {
		Service service = beanDefines.get(serviceName);
		if(service.getBefore()!=null){
			invokeBefore(service.getBefore(),req,null);
		}
		try{
			Object result = null;
			if(beanDefines!=null){
				Class<?> clazz = classes.get(service.getClazz());
				if(clazz==null){
					throw new ServiceServerException("找不到 serviceName'" + serviceName + "'对应的类");
				}
				Object instance = beans.get(serviceName);
				if(instance==null){
					instance = classes.get(service.getClazz()).newInstance();
				}
				Method method = ClassMethod.getMethod(clazz, req.getMethod(),req.getParameterTypes());
				if(method!=null){
					if(req.getParameterTypes()==null){
						result = method.invoke(instance);
					}else{
						result = method.invoke(instance, req.getParams());
					}
				}else{
					throw new ServiceServerException("找不到 serviceName '" + serviceName + "'类中'" + req.getMethod() + "(" +  req.getParameterTypes() + ")'方法");
				}
			}else{
				throw new ServiceServerException("找不到 serviceName '" + serviceName + "'的服务");
			}
			if(service.getReturning()!=null){
				invokeReturning(service.getReturning(),req,result);
			}
			return result;
		}catch(ServiceServerException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw e;
		}catch(InvocationTargetException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e.getTargetException());
		}catch(IllegalAccessException | IllegalArgumentException | InstantiationException 
				| SecurityException | NotFoundException | NoSuchMethodException | ClassNotFoundException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e);
		}
	}
	
	/**
	 * 初始化回调方方法
	 * @param serviceName
	 * @param req
	 * @param res
	 * @return
	 * @throws ServiceServerException
	 */
	public Object invokeBefore(String serviceName,ServiceRequest req,Object res) throws ServiceServerException {
		Service service = beanDefines.get(serviceName);
		if(service.getBefore()!=null){
			invokeBefore(service.getBefore(),req,null);
		}
		try{
			Object result = null;
			if(beanDefines!=null){
				Class<?> clazz = classes.get(service.getClazz());
				if(clazz==null){
					throw new ServiceServerException("找不到 serviceName'" + serviceName + "'对应的类");
				}
				Object instance = beans.get(serviceName);
				if(instance==null){
					instance = classes.get(service.getClazz()).newInstance();
				}
				List<ClassMethodParamDefine> methods = ClassMethod.getMethods(clazz, "before");
				if(methods!=null && methods.size()==1){
					result = methods.get(0).getMethod().invoke(instance, req);
				}else{
					throw new ServiceServerException("找不到 serviceName '" + serviceName + "'类中'init'方法");
				}
			}else{
				throw new ServiceServerException("找不到 serviceName '" + serviceName + "'的服务");
			}
			if(service.getReturning()!=null){
				invokeReturning(service.getReturning(),req,result);
			}
			return result;
		}catch(ServiceServerException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw e;
		}catch(InvocationTargetException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e.getTargetException());
		}catch(IllegalAccessException | IllegalArgumentException | InstantiationException 
				| SecurityException | NotFoundException | NoSuchMethodException | ClassNotFoundException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e);
		}
	}

	/**
	 * 出错后回调方法
	 * @param serviceName
	 * @param req
	 * @param res
	 * @return
	 * @throws ServiceServerException
	 */
	public Object invokeThrowing(String serviceName,ServiceRequest req,Throwable res) throws ServiceServerException {
		Service service = beanDefines.get(serviceName);
		if(service.getBefore()!=null){
			invokeBefore(service.getBefore(),req,null);
		}
		try{
			Object result = null;
			if(beanDefines!=null){
				Class<?> clazz = classes.get(service.getClazz());
				if(clazz==null){
					throw new ServiceServerException("找不到 serviceName'" + serviceName + "'对应的类");
				}
				Object instance = beans.get(serviceName);
				if(instance==null){
					instance = classes.get(service.getClazz()).newInstance();
				}
				List<ClassMethodParamDefine> methods = ClassMethod.getMethods(clazz, "throwing");
				if(methods!=null && methods.size()==1){
					result = methods.get(0).getMethod().invoke(instance, req,res);
				}else{
					throw new ServiceServerException("找不到 serviceName '" + serviceName + "'类中'init'方法");
				}
			}else{
				throw new ServiceServerException("找不到 serviceName '" + serviceName + "'的服务");
			}
			if(service.getReturning()!=null){
				invokeReturning(service.getReturning(),req,result);
			}
			return result;
		}catch(ServiceServerException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw e;
		}catch(InvocationTargetException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e.getTargetException());
		}catch(IllegalAccessException | IllegalArgumentException | InstantiationException 
				| SecurityException | NotFoundException | NoSuchMethodException | ClassNotFoundException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e);
		}
	}

	/**
	 * 完成后回调方法
	 * @param serviceName
	 * @param req
	 * @param res
	 * @return
	 * @throws ServiceServerException
	 */
	public Object invokeReturning(String serviceName,ServiceRequest req,Object res) throws ServiceServerException {
		Service service = beanDefines.get(serviceName);
		if(service.getBefore()!=null){
			invokeBefore(service.getBefore(),req,null);
		}
		try{
			Object result = null;
			if(beanDefines!=null){
				Class<?> clazz = classes.get(service.getClazz());
				if(clazz==null){
					throw new ServiceServerException("找不到 serviceName'" + serviceName + "'对应的类");
				}
				Object instance = beans.get(serviceName);
				if(instance==null){
					instance = classes.get(service.getClazz()).newInstance();
				}
				List<ClassMethodParamDefine> methods = ClassMethod.getMethods(clazz, "returning");
				if(methods!=null && methods.size()==1){
					result = methods.get(0).getMethod().invoke(instance, req,res);
				}else{
					throw new ServiceServerException("找不到 serviceName '" + serviceName + "'类中'back'方法");
				}
			}else{
				throw new ServiceServerException("找不到 serviceName '" + serviceName + "'的服务");
			}
			if(service.getReturning()!=null){
				invokeReturning(service.getReturning(),req,result);
			}
			return result;
		}catch(ServiceServerException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw e;
		}catch(InvocationTargetException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e.getTargetException());
		}catch(IllegalAccessException | IllegalArgumentException | InstantiationException 
				| SecurityException | NotFoundException | NoSuchMethodException | ClassNotFoundException e){
			if(service.getThrowing()!=null){
				invokeThrowing(service.getThrowing(),req,e);
			}
			throw new ServiceServerException("执行 serviceName '" + serviceName + "'服务出错",e);
		}
	}
}
